var fs=require('fs');
var gd=require('gd');
var Process=require('process').Process;
var exif_reader = require("exif").Reader;

/*****************************************************************************/
exports.functions={
	/*
		Function: functions.to_latin

		Converts text to latin, used for transliteration
	*/
	to_latin: function(space,src) {
		for (var i=0,s=to_latin_src.length;i<s;i++) {
			src=src.replace(to_latin_src[i],to_latin_dst[i]);
		}
		return src;
	},
	/*
		Function: functions.gen_calc_code

		Generates a calculateable unique code based on some name.
		Can be used for things like making a valid URL based on article or news name.

		Parameters:
			model - model object, containing:
			* model.id - (optional) an id of existing entry in database
			* model.ModelName - a name of model
			* model[src_field] - an original name to use
			* model[dst_field] - (optional) a calculated name to store data
			src_field - field name in object
			dst_field - field name in object

		Returns:
			none
			* model[dst_field] is filled with a result
	*/
	gen_calc_code: function(space,model,src_field,dst_field) {
		var code_src=space.site.refs.functions.to_latin(space,model[src_field]);
		if (code_src.length>240) code_src=code_src.substr(0,240);
		var j=0;
		var flag=true;
		var code=code_src;
		while (flag==true) {
			var h={limit: 1};
			if (model.id) h.id={type: "<>",value: model.id};
			h[dst_field]=code;
			var m=space.site.mfact.list(model.ModelName,h);
//			throw(space.site.functions.Dumper([h,m]));
//			throw([h.limit,h.id.value,h[dst_field],m]);
			if (m.length!=0) {
				j++;
				code=code_src+"-"+j;
			} else {
				flag=false;
			}
		}
		model[dst_field]=code;
	},
	/*
		Function: functions.tagger_save
	*/
	tagger_save: function(space) {
	},
		/*
		Function: functions.file_update_stats

		Updates file stats, that is - width, height, filesize, seconds (if available)

		Parameters:
			file_id - id in Tfiles

		Returns:
			none
	*/
	file_update_stats: function(space,file_id) {
		var href={
			file_id:file_id,
			width: null,
			height: null,
			filesize: null,
			seconds: null
		};
		var file=space.site.sql.execute_and_fetch_one("files/get",href);
		var path=space.site.paths.html+space.functions.file_group_path(space,file.file_group_id);
		var filename=path+file.id+"."+file.ext;
		href.filesize=new fs.File(filename).stat().size;
//		throw space.Dumper([filename,href.filesize]);
		switch (1*file.type_id) {
			case 1: // Image
				var image_type=space.functions.gd_image_type_by_ext(space,file.ext);
				var image=new gd.Image(image_type,filename);
				href.width=image.sx();
				href.height=image.sy();
				break;
			case 2: // Video
				break;
			case 3: // Sound
				break;
			case 4: // Other
				return;
				break;
		}
//		throw space.Dumper(href);
		space.site.sql.execute("files/set_stats",href);
	},
	/*
		Function: functions.all_files_update_stats

		Updates stats of all files

		Parameters:

		Returns:
			none
	*/
	all_files_update_stats: function(space) {
		space.site.sql.execute_and_fetch_single("select id from Tfiles").forEach(function(x) {
			space.functions.file_update_stats(space,x.id);
		});
	},
	/*
		Function: functions.file_delete

		Deletes a file from a filesystem and from a Tfiles table in database

		Parameters:
			file_id - id in Tfiles

		Returns:
			none
	*/
	file_delete: function(space,file_id) {
		var href={file_id:file_id};
		var file=space.site.sql.execute_and_fetch_one("files/get",href);
		var path=space.site.paths.html+space.functions.file_group_path(space,file.file_group_id);
		var pfiles=new fs.Directory(path).listFiles();
		var re=new RegExp("^"+file_id+"(\\.|-preview)");
		pfiles.forEach(function(pfile) {
			if (pfile.match(re)) (new fs.File(path+pfile)).remove();
		});
		space.site.sql.execute("files/delete",href);
	},
	/*
		Function: functions.recurse_object

		TODO dont know if it is used
	*/
	recurse_object: function(space,object,callback) {
		if (typeof(object)!="object") return;
		if (object.constructor==Array) {
			for (var i=0;i!=object.length;i++) {
				var old=object[i];
				object[i]=callback(space,"array",i,old);
				if (object[i]!==old) continue;
				if (typeof(object[i])=="object") space.functions.recurse_object(space,object[i],callback);			
			}
			return;
		}
		for (var k in object) {
			var old=object[k];
			object[k]=callback(space,"object",k,old);
			if (object[k]!==old) continue;
			if (typeof(object[k])=="object") space.functions.recurse_object(space,object[k],callback);
		}
	},
	/*
		Function: functions.files_load

		Loads files from certain file_group and builds their urls

		Parameters:
			file_group_id - an ID in Tfile_groups table

		Returns:
			Array of file objects
	*/
	files_load: function(space,file_group_id) {
		var r=space.site.sql.execute_and_fetch("files/list",{file_group_id:file_group_id});
		var fgpath=space.functions.file_group_path(space,file_group_id);
		r.forEach(function(x) {
			x.url=fgpath+x.id+"."+x.ext;
		});
		return r;
	},
	/*
		Function: functions.make_file_group_path

		Parameters:
			fgpath - an array of folder names, such as ["my images","summer 2012","visit to grandma"]
			uid - user to create folders
		Returns:
			array of fg_id
	*/
	make_file_group_path: function(space,fgpath,uid) {
		var ret=[];
		var parent_id=0;
		var basepath=space.site.paths.html;
		for (var i=0;i<fgpath.length;i++) {
			var fg=space.site.sql.execute_and_fetch_one("file_groups/get_by_name_and_parent",{name:fgpath[i],parent_id:parent_id});
			if (!fg) {
				space.site.sql.execute("file_groups/insert",{parent_id:parent_id,name:fgpath[i],user_cr_id:uid||space.uid});
				fg=space.site.sql.execute_and_fetch_one("file_groups/get_by_name_and_parent",{name:fgpath[i],parent_id:parent_id});
				var path=space.functions.file_group_path(space,fg.id);
				space.functions.mkdir_rec(basepath,path);
			}
			ret.push(fg.id);
			parent_id=fg.id;
		}
//		throw space.Dumper({fgpath: fgpath, path:path, files:space.req.files, ret:ret});
		return ret;
	},
	/*
		Function: functions.mksid
		
		Generates a unique SID

		Returns:
			A string length of 48 symbols
	*/
	mksid: function() {
		var sid_items="1234567890qwertyuiopasdfghjklzxcvbnm";
		var r="";
		for (var i=0;i<48;i++) {
			r+=sid_items.substr(Math.floor(Math.random()*sid_items.length),1);
		}
		return r;
	},
	/*
		Function: functions.get_option
		
		Paramaters:
			params - an array of names through which to follow to result option value
		Returns:
			A value
	*/
	get_option: function(space,params) {
		var arr=["site","system"];
		for (var j=0;j<arr.length;j++) {
			var a=space[arr[j]];
			for (var i=0;i<params.length;i++) {
				if (!(params[i] in a)) break;
				a=a[params[i]];
				if (i==params.length-1) return a;
			}
		}
		return undefined;
	},

	/*
		Function: functions.date_format

		Parameters:
			d - Date object
		Returns:
			date string, formatted to DD.MM.YYYY
	*/
	date_format: function(space,d) {
		var dd=d.getDate();
		var mm=d.getMonth()+1;
		var yyyy=d.getFullYear();
		return ""+(dd<10?"0":"")+dd+"."+(mm<10?"0":"")+mm+"."+yyyy;
	},

	/*
		Function: functions.date_add

		Parameters:
			d - Date object
			value - a value to add
			type - type of value, "day", "month" or "year"
		Returns:
			Date object
	*/
	date_add: function (space,d,value,type) {
		var r=new Date(d.getTime());
		switch (type) {
			case "day":
				r.setDate(r.getDate()+value);
				break;
			case "month":
				r.setMonth(r.getMonth()+value);
				break;
			case "year":
				r.setFullYear(r.getFullYear()+value);
				break;
		}
		return r;
	},

	date_new: function(space,text) {
		var arr=text.match(/^(\d\d)\.(\d\d)\.(\d\d\d\d)$/);
		if (!arr) return undefined;
		return new Date(arr[3],arr[2]-1,arr[1]);
	},
	/*
		Function: functions.import_files
		Parameters:
		Returns:
	*/
	import_files: function(space,path,user,folder) {
		var folder_id;
		if (folder.match(/^\d+$/)) {
			folder_id=folder;
		} else {
			folder_id=space.site.sql.execute_and_fetch_one("file_groups/get_by_code",{code:folder});
			if (folder_id) {
				folder_id=folder_id.id;
			} else {
				folder_id=space.site.sql.execute_and_fetch_one("file_groups/get_by_name",{name:folder}).id;
			}
		}
		var user_id;
		if (user.match(/^\d+$/)) {
			user_id=user;
		} else {
			user_id=space.site.sql.execute_and_fetch_one("users/get_by_login",{login:user}).id;
		}
		var d=new fs.Directory(path);
		if (!d.exists()) throw("No path!");
		space.fields={};
		space.roles={};
		space.roles.files=1;
		space.req={};
		space.req.files={};
		d.listFiles().sort().forEach(function(filename) {
			if (filename.match(/^\./)) return;
			var options={
				fg_id:folder_id,
				uid:user_id,
				inputname: "aaa",
				downscale_policy: {
					x: -1,
					y: -1
				}
			};
			space.req.files.aaa={
				originalName: filename,
				existingfile: path+"/"+filename
			};
			space.functions.user_upload_file(space,options);
		});
		return "";
	}
};

exports.controllers={
	/*
		Function: controllers.get_option

		Returns:
			An option from space.site[param] or space.system[param]
	*/
	get_option: function(space,param) {
		return space.functions.get_option(space,param.split(/\./));
	},
	/*
		Function: controllers.rewrite_redirect

		Can be used when making rewrites

		Parameters:
			params - (optional) hash of:
			params.url - Location to make a redirect
			rewr - (optional) A page to redirect to
	*/
	rewrite_redirect: function(space,params,rewr) {
		if (!params) params={url:rewr.alias};
//		Status: 302 Found
//		Location: http://somewhere.else/in/movie/land
		space.page.statusCode="302";
		space.page.responseHeaders={"Location":params.url};
		return undefined;
	},
	/*
		Function: controllers.mfact_list

		TODO WHAT IS THAT?

		Parameters:
			params - A hash, containing ModelName and filtering rules.
		
		Returns:
			Returns an array of models
	*/
	mfact_list: function(space,params) {
		var filter={};
		for (var k in params) {
			if (k=="ModelName") continue;
			filter[k]=params[k];
		}
		return space.mfact.list(params.ModelName,filter);
	},

	/*
		Function: controllers.embeded_text

		Parameters:
			code from Tembeded_texts

		Returns:
			body.
	*/
	embeded_text: function(space,params) {
		var et=space.mfact.get("embeded_text",{code:params});
		if (!et) return "<b>[ET "+params+"]</b>";
		return et.body;
	},
	
	/*
		Function: controllers.same_page
		
		Parameters:
			params - a hash with parameter names to skip
			params.add_tail - if ==1, then add ? or & to the end of url

		Returns:
			URL
	*/
	same_page: function(space,params) {
		var r=space.action_src||space.action;
		var i=0;
		for (var k in space.fields) {
			if (params[k]) continue;
			if (space.std_rewrite_fields && space.std_rewrite_fields[k]) continue;
			r+=i?"&":"?";
			r+=k;
			r+="=";
			r+=space.fields[k];
			i++;
		}
		if (params.add_tail) r+=i?"&":"?";
		return r;
	},
	/*
		Function: controllers.paginator

		Parameters:
			params - a hash of:
			params.template		- a template to render, defaults to 'paginator/body'
			params.ap_value		- active page
			params.ap_name		- (if ap_value is not used) a name of field in space to use for active page
			params.cntp_value	- pages count
			params.cntp_name	- (if cntp_value is not used) a name of field in space to use for count of pages
			params.cntv_value	- values count, divided by page_size if cntp_* are not used
			params.cntv_name	- 
			params.page_size	- page size, needed when cntv_* used
	*/
	paginator: function(space,params) {
		var ap;
		if (params.ap_value) {
			ap=params.ap_value;
		} else if (params.ap_name) {
			ap=space[params.ap_name];
		} else {
			ap=space.fields.page||0;
		}
		ap=ap*1;
		var cntp;
		if (params.cntp_value) {
			cntp=params.cntp_value;
		} else if (params.cntp_name) {
			cntp=space[params.cntp_name];
		} else if (params.cntv_value) {
			cntp=Math.ceil(params.cntv_value/params.page_size);
		} else if (params.cntv_name) {
			cntp=Math.ceil(space[params.cntv_name]/params.page_size);
		} else {
			throw "Misconfigured paginator()";
		}
		var p=space.paginator=[];
		var baseurl=space.controllers.same_page(space,{page:1,add_tail:1})+"page=";
		function add_pages(start,end) {
			for (var i=start;i<end;i++) {
				p.push({url: baseurl+i,n:i+1,active: ap==i?1:0});
			}
		}
		if (cntp<=10) {
			add_pages(0,cntp);
		} else {
			if (ap<5) {
				add_pages(0,6);p.push({split:1});add_pages(cntp-1,cntp);
			} else if (ap>=cntp-5) {
				add_pages(0,1);p.push({split:1});add_pages(cntp-6,cntp);
			} else {
				add_pages(0,1);p.push({split:1});add_pages(ap-3,ap+4);p.push({split:1});add_pages(cntp-1,cntp);
			}
		}
		if (ap!=0) space.prev_page_url=baseurl+(ap-1);
		if (ap<cntp-1) space.next_page_url=baseurl+(ap+1);
		return space.views.process("widgets/"+(params.template||"paginator/body"),space);
	},

	/*

		Parameters:
			params - a hash of
			params.model_name
			params.filter
			params.page_size
			params.paginator_template - (can be empty)

		Returns:
			a hash of:
				return.fetched_models - array of models
				return.paginator_result - an HTML part of paginator
				return.prev_page_url
				return.next_page_url
	*/
	paginator_model: function(space,params) {
		if (!params.filter) params.filter={};
		var cnt=space.mfact.count(params.model_name,params.filter);
		params.filter.limit=params.page_size;
		params.filter.offset=params.page_size*(space.fields.page||0);
		var part=space.models=space.mfact.list(params.model_name,params.filter);

		var paginator_result=space.controllers.paginator(space,{
			template: params.paginator_template,
			cntv_value: cnt,
			page_size: params.page_size
		});
		var baseurl=space.controllers.same_page(space,{page:1,add_tail:1})+"page=";
		var ret={
			paginator_result: paginator_result,
			fetched_models: part
		};
		var ap=1*(space.fields.page||0)
		if (ap!=0) ret.prev_page_url=baseurl+(ap-1);
		if (ap<Math.ceil(cnt/params.page_size)-1) ret.next_page_url=baseurl+(ap+1);
		return ret;
	},

	/*
		Parameters:
			params.template
			PLUS all params of paginator_model

		Returns:
			A template, rendered with extra space values taken from hash of paginator_model
	*/
	paginator_model_html: function(space,params) {
		var a=space.controllers.paginator_model(space,params);
		for (var k in a) space[k]=a[k];
		return space.views.process("widgets/"+params.template,space);
	},

	mobile_map_site: function(space,options) {
		var protocol="http://";
		if (options && options.protocol) protocol=options.protocol;
		if (system.env.HTTP_USER_AGENT.match(/iphone|ipad/i)) return protocol+"maps.apple.com/maps?q=";
		return protocol+"maps.google.com/maps?q=";
	}
};
/*****************************************************************************/

